package person.burgess.regexandgame.regex.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import person.burgess.regexandgame.regex.model.Field;

/**
 * 
 * Content Matcher
 * 
 * @author Burgess Li
 *
 */
public class ContentMatcher {
	
	private static ContentMatcher contentMatch = null;
	
	private ContentMatcher () {}
	
	/**
	 * 
	 * You can use this static method to get the singleton instance
	 * 
	 * @return Content matcher instance
	 */
	public static ContentMatcher getInstance () {
		if (contentMatch == null) {
			synchronized (ContentMatcher.class) {
				if (contentMatch == null)
					contentMatch = new ContentMatcher();
			}
		}
		return contentMatch;
	}

	/**
	 * 
	 * This method allows you to customize the matching characters and get the matching location information, 
	 * but note that this match ignores case.
	 * 
	 * @param keywords Keywords set for match
	 * @param content The content which needs to be matched
	 * @return The key is the keyword, and the value is the Field list, which contains the matching information
	 */
	public HashMap<String, ArrayList<Field>> match (Set<String> keywords, String content) {
		if (keywords == null || content == null) {
			return null;
		}
		// Initialize Map
		HashMap<String, ArrayList<Field>> resultMap = new HashMap<String, ArrayList<Field>>();
		for (String keyword: keywords) {
			resultMap.put(keyword, new ArrayList<Field>());
		}
		// Generate Regex
		StringBuilder regexBuilder = new StringBuilder();
		regexBuilder.append("(");
		regexBuilder.append(String.join("|", keywords));
		regexBuilder.append(")+?");
		// Match with CASE_INSENSITIVE
		Pattern pattern = Pattern.compile(regexBuilder.toString(), Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(content);
		String keyTemp = "";
		while (matcher.find()) {
			keyTemp = content.substring(matcher.start(), matcher.end());
			if (resultMap.containsKey(keyTemp.toLowerCase())) {
				resultMap.get(keyTemp.toLowerCase()).add(new Field(keyTemp, matcher.start(), matcher.end()));
			}
		}
		return resultMap;
	}
	
}
